package com.ruoyi.business.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.business.domain.TChat;
import com.ruoyi.business.domain.vo.TChatVo;
import com.ruoyi.business.service.IChatService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Component
@ServerEndpoint("/chat/{userId}")
public class ChatWebSocket {

    private static final IChatService chatService = SpringUtils.getBean(IChatService.class);

    // 存储当前对象
    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();

//    private static RedisTemplate<Object, Object> redisTemplate = null;
    private static final RedisTemplate<Object, Object> redisTemplate = SpringUtils.getBean("ObjObjRedisTemplate");


    private static final ISysUserService userService = SpringUtils.getBean(ISysUserService.class);

    private static final String CHAT_KEY_TEMPLATE = "chat_classId::%s";


    public String convertKey(String id) {
        return String.format(CHAT_KEY_TEMPLATE, id);
    }

    public List<Session> getSessionListByClassId(String classId, String userId) {
        // 从redis中获取对应班级所有的用户信息
        Set<Object> members = redisTemplate.opsForSet().members(convertKey(classId));
        assert members != null;
        return members.stream().map(item -> {
            try {
                SysUser sysUser = (SysUser) item;
                Session s = null;
//                if (!sysUser.getUserId().equals(userId)) {
                    s = sessionMap.get(sysUser.getUserId());
//                }
                return s;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }

    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) throws IOException {
        sessionMap.put(userId, session);
        // 查询当前用户所在班级
        SysUser sysUser = getUser(userId);
        // 将当前用户信息加入到redis中
        redisTemplate.opsForSet().add(convertKey(sysUser.getMyClass()), sysUser);
        List<Session> sessionList = getSessionListByClassId(sysUser.getMyClass(), userId);
        List<SysUser> members = getOnlineUsers(sysUser);
        JSONArray jsonArray = (JSONArray) JSONObject.toJSON(members);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userList", jsonArray);
        jsonObject.put("type", "open");
        for (Session s : sessionList) {
            s.getBasicRemote().sendText(jsonObject.toJSONString());
        }
    }

    private List<SysUser> getOnlineUsers(SysUser sysUser) {
        Set<Object> members = redisTemplate.opsForSet().members(convertKey(sysUser.getMyClass()));
        if (members != null) {
            return members.stream().filter(item -> {
                SysUser user = (SysUser) item;
                if (sessionMap.containsKey(user.getUserId())) {
                    return true;
                }
                return false;
            }).map(item -> (SysUser) item).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    private SysUser getUser(String userId) {
        SysUser sysUser = userService.selectUserById(userId);
        SysUser toRedis = new SysUser();
        toRedis.setUserId(sysUser.getUserId());
        toRedis.setUserName(sysUser.getUserName());
        toRedis.setAvatar(sysUser.getAvatar());
        toRedis.setMyClass(sysUser.getMyClass());
        return toRedis;
    }

    @OnClose
    public void onClose(@PathParam("userId") String userId) throws IOException {
        // 查询当前用户所在班级
        SysUser sysUser = getUser(userId);
        sessionMap.remove(userId);
        redisTemplate.opsForSet().remove(convertKey(sysUser.getMyClass()), sysUser);
        List<Session> sessionList = getSessionListByClassId(sysUser.getMyClass(), userId);
        List<SysUser> members = getOnlineUsers(sysUser);
        JSONArray jsonArray = (JSONArray) JSONObject.toJSON(members);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userList", jsonArray);
        jsonObject.put("type", "close");
        for (Session s : sessionList) {
            s.getBasicRemote().sendText(jsonObject.toJSONString());
        }
    }


    @OnMessage
    public void onMessage(String message, @PathParam("userId") String userId) throws IOException {
        // 查询当前用户所在班级
        SysUser sysUser = userService.selectUserById(userId);
        TChat chat = new TChat();
        chat.setUserId(Long.valueOf(userId));
        chat.setContext(message);
        chat.setClassId(Long.valueOf(sysUser.getMyClass()));
        chat.setCreateTime(System.currentTimeMillis());
        chatService.save(chat);
        // 从redis中获取对应班级所有的用户信息
        List<SysUser> members = getOnlineUsers(sysUser);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        if (members != null) {
            for (Object member : members) {
                SysUser user = (SysUser) member;
                Session session = sessionMap.get(user.getUserId());
                TChatVo vo = new TChatVo();
                BeanUtils.copyProperties(chat, vo);
                vo.setUser(sysUser);
                vo.setCreateTime(sdf.format(new Date(chat.getCreateTime())));
                if (user.getUserId().equals(userId)) {
                    vo.setIsOwn(true);
                }else {
                    vo.setIsOwn(false);
                }
                JSONObject jsonObject = (JSONObject) JSONObject.toJSON(vo);
                jsonObject.put("type", "message");
                session.getBasicRemote().sendText(jsonObject.toJSONString());
            }
        }
    }

}
